package org.framework.lazy.cloud.network.heartbeat.server.netty.permeate.tcp.advanced;


import com.alibaba.fastjson.JSON;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.framework.lazy.cloud.network.heartbeat.common.ChannelContext;
import org.framework.lazy.cloud.network.heartbeat.common.advanced.payload.NettyChannelContext;
import org.framework.lazy.cloud.network.heartbeat.common.constant.ProxyMessageType;
import org.framework.lazy.cloud.network.heartbeat.common.constant.TcpMessageType;
import org.framework.lazy.cloud.network.heartbeat.common.advanced.payload.NettyProxyMsg;
import org.framework.lazy.cloud.network.heartbeat.common.advanced.permeate.tcp.server.AbstractHandleTcpClientConnectSuccessTypeAdvanced;
import org.framework.lazy.cloud.network.heartbeat.common.utils.ChannelAttributeKeyUtils;
import org.framework.lazy.cloud.network.heartbeat.protocol.route.ClientProxyRoute;
import org.framework.lazy.cloud.network.heartbeat.protocol.route.RouteType;
import org.framework.lazy.cloud.network.heartbeat.protocol.route.ServerProxyRoute;
import org.framework.lazy.cloud.network.heartbeat.server.properties.ServerNodeProperties;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.*;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.command.lazy.netty.client.permeate.client.mapping.LazyClientPermeateClientMappingQueryListCommand;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.command.lazy.netty.client.permeate.server.mapping.LazyClientPermeateServerMappingQueryListCommand;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.command.lazy.netty.client.state.LazyNettyClientLoginCommand;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.command.lazy.netty.client.virtual.route.LazyNettyClientVirtualRouteQueryListCommand;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.command.lazy.netty.server.virtual.route.LazyNettyServerVirtualRouteQueryListCommand;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.dto.*;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.domain.model.lazy.netty.client.blacklist.LazyNettyClientBlacklist;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Role;
import org.springframework.stereotype.Component;
import org.wu.framework.web.response.Result;

import java.nio.charset.StandardCharsets;
import java.util.List;


/**
 * 服务端连接成功处理
 * TCP_REPORT_CLIENT_CONNECT_SUCCESS
 */
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@Slf4j
@Component
public class ServerHandleTcpClientConnectSuccessTypeAdvanced extends AbstractHandleTcpClientConnectSuccessTypeAdvanced<NettyProxyMsg> {

    private final LazyClientStatsChangeApplication lazyClientStatsChangeApplication;
    private final LazyNettyClientBlacklistApplication lazyNettyClientBlacklistApplication;
    private final LazyServerPermeateClientMappingApplication lazyServerPermeateClientMappingApplication;
    private final LazyClientPermeateServerMappingApplication lazyClientPermeateServerMappingApplication;
    private final LazyClientPermeateClientMappingApplication lazyClientPermeateClientMappingApplication;

    private final LazyNettyServerVirtualRouteApplication lazyNettyServerVirtualRouteApplication;
    private final LazyNettyClientVirtualRouteApplication lazyNettyClientVirtualRouteApplication;
    private final LazyNettyClientTokenBucketApplication lazyNettyClientTokenBucketApplication;

    private final ServerNodeProperties serverNodeProperties;

    public ServerHandleTcpClientConnectSuccessTypeAdvanced(LazyClientStatsChangeApplication lazyClientStatsChangeApplication, LazyNettyClientBlacklistApplication lazyNettyClientBlacklistApplication, LazyServerPermeateClientMappingApplication lazyServerPermeateClientMappingApplication, LazyClientPermeateServerMappingApplication lazyClientPermeateServerMappingApplication, LazyClientPermeateClientMappingApplication lazyClientPermeateClientMappingApplication, LazyNettyServerVirtualRouteApplication lazyNettyServerVirtualRouteApplication, LazyNettyClientVirtualRouteApplication lazyNettyClientVirtualRouteApplication, LazyNettyClientTokenBucketApplication lazyNettyClientTokenBucketApplication, ServerNodeProperties serverNodeProperties) {
        this.lazyClientStatsChangeApplication = lazyClientStatsChangeApplication;
        this.lazyNettyClientBlacklistApplication = lazyNettyClientBlacklistApplication;
        this.lazyServerPermeateClientMappingApplication = lazyServerPermeateClientMappingApplication;
        this.lazyClientPermeateServerMappingApplication = lazyClientPermeateServerMappingApplication;
        this.lazyClientPermeateClientMappingApplication = lazyClientPermeateClientMappingApplication;
        this.lazyNettyServerVirtualRouteApplication = lazyNettyServerVirtualRouteApplication;
        this.lazyNettyClientVirtualRouteApplication = lazyNettyClientVirtualRouteApplication;
        this.lazyNettyClientTokenBucketApplication = lazyNettyClientTokenBucketApplication;
        this.serverNodeProperties = serverNodeProperties;
    }


    /**
     * 处理当前数据
     *
     * @param nettyChannelContext 当前通道
     * @param msg        通道数据
     */
    @Override
    public void doHandler(NettyChannelContext nettyChannelContext, NettyProxyMsg msg) {

        Channel newChannel = nettyChannelContext.channel();
        String clientId = msg.getClientIdString();
        String appKey = msg.getAppKeyString();
        String appSecret = msg.getAppSecretString();
        String originalIp = msg.getOriginalIpString();
        ChannelContext.push(newChannel, clientId);

        ChannelAttributeKeyUtils.buildClientId(newChannel, clientId);
        ChannelAttributeKeyUtils.buildAppKey(newChannel, appKey);
        ChannelAttributeKeyUtils.buildAppSecret(newChannel, appSecret);
        ChannelAttributeKeyUtils.buildOriginalIp(newChannel, originalIp);

        // 客户端:{}，IP:{}连接成功
        log.info("Client: {}, IP: {} Connection successful", new String(msg.getClientId()), newChannel.remoteAddress().toString());
        // 验证客户端是否时黑名单
        LazyNettyClientBlacklist lazyNettyClientBlacklist = new LazyNettyClientBlacklist();
        lazyNettyClientBlacklist.setClientId(clientId);
        lazyNettyClientBlacklist.setIsDeleted(false);
        lazyNettyClientBlacklistApplication.exists(lazyNettyClientBlacklist).accept(exists -> {
            if (!exists) {
                // 认证验证
                Result<Boolean> existsTokenResult = lazyNettyClientTokenBucketApplication.certificationToken(clientId, appKey, appSecret);
                Boolean existsToken= existsTokenResult.getData();
                Boolean enableTokenVerification = serverNodeProperties.getEnableTokenVerification();
                existsToken = enableTokenVerification ? existsToken : true;
                if(existsToken){
                    // 服务状态在线
                    LazyNettyClientLoginCommand lazyNettyClientLoginCommand = new LazyNettyClientLoginCommand();
                    lazyNettyClientLoginCommand.setClientId(clientId);
                    lazyNettyClientLoginCommand.setAppKey(appKey);
                    lazyNettyClientLoginCommand.setAppSecret(appSecret);
                    lazyNettyClientLoginCommand.setOriginalIp(originalIp);
                    lazyClientStatsChangeApplication.clientOnLine(lazyNettyClientLoginCommand);
                    // 当前在线客户端数量:{}
                    log.info("Current number of online clients: {}", ChannelContext.getClientIds().size());
                    // 所有的客户端ID
                    List<String> clientIdList = ChannelContext.getClientIds();

                    // TODO 多副本本地channel 无法共享问题
                    // 通知所有客户端有人上线了
                    ChannelContext.getChannels().forEach((existClientId, channels) -> {
                        NettyProxyMsg nettyMsg = new NettyProxyMsg();
                        nettyMsg.setType(TcpMessageType.TCP_DISTRIBUTE_CLIENT_CONNECTION_SUCCESS_NOTIFICATION);
                        nettyMsg.setData((JSON.toJSONString(clientIdList)
                                .getBytes(StandardCharsets.UTF_8)));
                        // 发送所有客户端ID
                        for (Channel channel : channels) {
                            channel.writeAndFlush(nettyMsg);
                        }
                    });
                    // 开始开启客户端：【{}】,端口映射
                    log.info("Start opening client: [{}], port mapping", clientId);
                    // 创建访问者（内网穿透连接创建）
                    lazyServerPermeateClientMappingApplication.createVisitor(clientId);
                    // 结束开启客户端：【{}】,端口映射
                    log.info("End opening client: [{}], port mapping", clientId);
                }else {
                    // 关闭通道
                    log.warn("无法认证客户端：【{}】",clientId);
                    newChannel.close();
                }


            } else {
                // 黑名单客户端

            }
        });
        // 查询客户端渗透服务端信息
        LazyClientPermeateServerMappingQueryListCommand lazyClientPermeateServerMappingQueryListCommand = new LazyClientPermeateServerMappingQueryListCommand();
        lazyClientPermeateServerMappingQueryListCommand.setClientId(clientId);
        lazyClientPermeateServerMappingQueryListCommand.setIsDeleted(false);
        lazyClientPermeateServerMappingApplication.findList(lazyClientPermeateServerMappingQueryListCommand)
                .accept(lazyInternalNetworkClientPermeateServerMappingDTOS -> {
                    for (LazyClientPermeateServerMappingDTO lazyClientPermeateServerMappingDTO : lazyInternalNetworkClientPermeateServerMappingDTOS) {

                        String permeateTargetIp = lazyClientPermeateServerMappingDTO.getPermeateTargetIp();
                        Integer permeateTargetPort = lazyClientPermeateServerMappingDTO.getPermeateTargetPort();
                        Integer visitorPort = lazyClientPermeateServerMappingDTO.getVisitorPort();
                        NettyProxyMsg nettyMsg = new NettyProxyMsg();
                        nettyMsg.setType(TcpMessageType.TCP_DISTRIBUTE_CLIENT_PERMEATE_SERVER_INIT);
                        nettyMsg.setClientTargetIp(permeateTargetIp);
                        nettyMsg.setClientTargetPort(permeateTargetPort);
                        nettyMsg.setVisitorPort(visitorPort);
                        newChannel.writeAndFlush(nettyMsg);
                    }
        });


        // 查询客户端渗透客户端信息
        LazyClientPermeateClientMappingQueryListCommand lazyClientPermeateClientMappingQueryListCommand = new LazyClientPermeateClientMappingQueryListCommand();
        lazyClientPermeateClientMappingQueryListCommand.setFromClientId(clientId);
        lazyClientPermeateClientMappingQueryListCommand.setIsDeleted(false);
        lazyClientPermeateClientMappingApplication.findList(lazyClientPermeateClientMappingQueryListCommand)
                .accept(lazyInternalNetworkClientPermeateServerMappingDTOS -> {
                    for (LazyClientPermeateClientMappingDTO lazyClientPermeateClientMappingDTO : lazyInternalNetworkClientPermeateServerMappingDTOS) {

                        String permeateTargetIp = lazyClientPermeateClientMappingDTO.getPermeateTargetIp();
                        Integer permeateTargetPort = lazyClientPermeateClientMappingDTO.getPermeateTargetPort();
                        Integer visitorPort = lazyClientPermeateClientMappingDTO.getVisitorPort();
                        String toClientId = lazyClientPermeateClientMappingDTO.getToClientId();
                        NettyProxyMsg nettyMsg = new NettyProxyMsg();
                        nettyMsg.setType(TcpMessageType.TCP_DISTRIBUTE_CLIENT_PERMEATE_CLIENT_INIT);
                        nettyMsg.setClientTargetIp(permeateTargetIp);
                        nettyMsg.setClientTargetPort(permeateTargetPort);
                        nettyMsg.setVisitorPort(visitorPort);
                        nettyMsg.setClientId(clientId);
                        nettyMsg.setData(toClientId.getBytes(StandardCharsets.UTF_8));
                        newChannel.writeAndFlush(nettyMsg);
                    }
                });
        // 下发服务端路由
        LazyNettyServerVirtualRouteQueryListCommand lazyNettyServerVirtualRouteQueryListCommand = new LazyNettyServerVirtualRouteQueryListCommand();
        lazyNettyServerVirtualRouteQueryListCommand.setIsDeleted(false);
        lazyNettyServerVirtualRouteApplication.findList(lazyNettyServerVirtualRouteQueryListCommand)
                .accept(lazyNettyServerVirtualRouteDTOS -> {
                    for (LazyNettyServerVirtualRouteDTO lazyNettyServerVirtualRouteDTO : lazyNettyServerVirtualRouteDTOS) {
                        String virtualIp = lazyNettyServerVirtualRouteDTO.getVirtualIp();
                        String virtualPort = lazyNettyServerVirtualRouteDTO.getVirtualPort();
                        String targetIp = lazyNettyServerVirtualRouteDTO.getTargetIp();
                        String targetPort = lazyNettyServerVirtualRouteDTO.getTargetPort();
                        ServerProxyRoute serverProxyRoute = new ServerProxyRoute();
                        serverProxyRoute.setServerIp("default");
                        serverProxyRoute.setVirtualIp(virtualIp);
                        serverProxyRoute.setVirtualPort(virtualPort);
                        serverProxyRoute.setTargetIp(targetIp);
                        serverProxyRoute.setTargetPort(targetPort);
                        serverProxyRoute.setRouteType(RouteType.CLIENT_PROXY_SEVER);
                        NettyProxyMsg nettyMsg = new NettyProxyMsg();
                        nettyMsg.setType(ProxyMessageType.HTTP_DISTRIBUTE_CLIENT_PROXY_SERVER_SERVER_ROUTE_);
                        nettyMsg.setData((JSON.toJSONString(serverProxyRoute)
                                .getBytes(StandardCharsets.UTF_8)));
                        newChannel.writeAndFlush(nettyMsg);
                    }
                });


        // 下发客户端路由
        LazyNettyClientVirtualRouteQueryListCommand lazyNettyClientVirtualRouteQueryListCommand =
                new LazyNettyClientVirtualRouteQueryListCommand();
        lazyNettyClientVirtualRouteQueryListCommand.setIsDeleted(false);
        lazyNettyClientVirtualRouteApplication.findList(lazyNettyClientVirtualRouteQueryListCommand)
                .accept(lazyNettyClientVirtualRouteDTOList -> {
                    for (LazyNettyClientVirtualRouteDTO lazyNettyClientRouteDTO : lazyNettyClientVirtualRouteDTOList) {
                        String virtualIp = lazyNettyClientRouteDTO.getVirtualIp();
                        String virtualPort = lazyNettyClientRouteDTO.getVirtualPort();
                        String targetClientId = lazyNettyClientRouteDTO
                                .getTargetClientId();
                        String targetIp = lazyNettyClientRouteDTO.getTargetIp();
                        String targetPort = lazyNettyClientRouteDTO.getTargetPort();

                        ClientProxyRoute clientProxyRoute = new ClientProxyRoute();

                        clientProxyRoute.setVirtualIp(virtualIp);
                        clientProxyRoute.setVirtualPort(virtualPort);
                        clientProxyRoute.setTargetClientId(targetClientId);
                        clientProxyRoute.setTargetIp(targetIp);
                        clientProxyRoute.setTargetPort(targetPort);
                        clientProxyRoute.setRouteType(RouteType.CLIENT_PROXY_CLIENT);
                        NettyProxyMsg nettyMsg = new NettyProxyMsg();
                        nettyMsg.setType(ProxyMessageType.HTTP_DISTRIBUTE_CLIENT_PROXY_SERVER_CLIENT_ROUTE_);
                        nettyMsg.setData((JSON.toJSONString(clientProxyRoute)
                                .getBytes(StandardCharsets.UTF_8)));
                        newChannel.writeAndFlush(nettyMsg);
                    }
                });

    }

}
